

/**CFile****************************************************************
 
  FileName    [app_delay.cpp] 

  SystemName  []

  PackageName []
  
  Synopsis    [基于ABC的电路延迟优化]

  Author      []
   
  Affiliation []

  Date        [2021.7.13]

***********************************************************************/
#include <iostream>
using namespace std;
#include <stdio.h>
#include <time.h>
#include "base/abc/abc.h"
#include "map/amap/amap.h"
#include "app.h"
#include "aig/aig/aig.h"
#include "simulatorPro.h"
#include "opt.h"
#include "delay.h"
#include <vector>
#include <map>
#include <string.h>
/*------------------------------------------------------------------------*/
/* 对电路进行工艺映射                                                    */
/*------------------------------------------------------------------------*/
extern "C" Abc_Ntk_t *Ntkmap(Abc_Ntk_t *pNtk)
{
    extern Abc_Ntk_t * Abc_NtkMap( Abc_Ntk_t * pNtk, double DelayTarget, double AreaMulti, double DelayMulti, float LogFan, float Slew, float Gain, int nGatesMin, int fRecovery, int fSwitching, int fSkipFanout, int fUseProfile, int fUseBuffs, int fVerbose );
    Amap_Par_t Pars, *pPars = &Pars;
    Amap_ManSetDefaultParams(pPars);
    Abc_Ntk_t *pNtkTemp = NULL;
    pNtk = Abc_NtkMap(pNtkTemp = pNtk, -1, 0, 0, 0, 0, 250, 0, 1, 0, 0, 0, 0, 0);
    Abc_NtkDelete(pNtkTemp);
    return pNtk;
}
/*------------------------------------------------------------------------*/
/* 主程序                                                                 */
/*------------------------------------------------------------------------*/
extern Abc_Ntk_t *App_GetBestDely(Abc_Ntk_t *pNtk, double bound)
{
    DelyNode delaynode;
    pNtk = GetBestDelayNtk(pNtk, delaynode, bound);
/*     cleardelaynode(pNtk, delaynode);
    setiTemp(pNtk);
    SaveMessage(pNtk, delaynode);
    CalWeight(pNtk, delaynode);
    sortbylevel(pNtk, delaynode);
    test(pNtk, delaynode); */
    return pNtk;
}
/*------------------------------------------------------------------------*/
/* 保存电路的PO并根据PO寻找关键路径                                          */
/*------------------------------------------------------------------------*/
void SaveMessage(Abc_Ntk_t *pNtk, DelyNode &delaynode)
{
    Abc_Obj_t *ppo = NULL, *pNode = NULL;
    int i = 0;
    int level = Abc_NtkLevel(pNtk);
    //保存当前电路与PO相连节点名称
    Abc_NtkForEachPo(pNtk, ppo, i)
    {
        //count用来记录po到pi遍历的节点个数，若遍历个数为当前电路的层级数，则记录该输出节点的关键路径节点集
        delaynode.count = 0;
        pNode = Abc_ObjFanin0(ppo);
        delaynode.topid.push_back(pNode->Id);
        delaynode.tempnode.clear();
        calPathDistance(pNtk, pNode, delaynode);
        if (delaynode.count == (level - 1))
        {
            delaynode.pathcone.push_back(pNode->Id);
            getCriticalPath(pNode, delaynode);
        }
    }
    //根据PO相连节点寻找到所有关键路径
    /*     for (i = 0; i < delaynode.topid.size(); i++)
    {
        delaynode.pathcone.push_back(delaynode.topid[i]);
        getCriticalPath(Abc_NtkObj(pNtk, delaynode.topid[i]), delaynode);
    } */
}
/*------------------------------------------------------------------------*/
/* 递归判定该PO到PI是否为关键路径                                         */
/*------------------------------------------------------------------------*/
void calPathDistance(Abc_Ntk_t *pNtk, Abc_Obj_t *pNode, DelyNode &delaynode)
{
    int flag = 0;
    Abc_Obj_t *pNode1 = NULL, *pNode2 = NULL;
    if (pNode->Level == 1)
    {
        return;
    }
    if (pNode->vFanins.nSize == 0)
    {
        return;
    }
    //判断节点层级是否相等
    if (Abc_ObjFanin0(pNode)->Level != Abc_ObjFanin1(pNode)->Level)
    {
        //选取层级较高的节点作为下一个探索初始节点
        pNode = Abc_ObjFanin0(pNode)->Level > Abc_ObjFanin1(pNode)->Level ? Abc_ObjFanin0(pNode) : Abc_ObjFanin1(pNode);
        for (int i = 0; i < delaynode.tempnode.size(); i++)
        {
            //判断当前节点层级是否已经计算过，若计算过则不进行层级计数
            if (pNode->Level == Abc_NtkObj(pNtk, delaynode.tempnode[i])->Level)
                flag = 1;
        }
        if (!flag)
        {
            delaynode.tempnode.push_back(pNode->Id);
            delaynode.count++;
        }
        calPathDistance(pNtk, pNode, delaynode);
    }
    else
    {
        pNode1 = Abc_ObjFanin0(pNode);
        pNode2 = Abc_ObjFanin1(pNode);
        for (int i = 0; i < delaynode.tempnode.size(); i++)
        {
            if (pNode1->Level == Abc_NtkObj(pNtk, delaynode.tempnode[i])->Level)
                flag = 1;
        }
        if (!flag)
        {
            delaynode.tempnode.push_back(pNode1->Id);
            delaynode.count++;
        }
        calPathDistance(pNtk, pNode1, delaynode);
        calPathDistance(pNtk, pNode2, delaynode);
    }
}

/*------------------------------------------------------------------------*/
/* 递归寻找关键路径节点                                                   */
/*------------------------------------------------------------------------*/
void getCriticalPath(Abc_Obj_t *pNode, DelyNode &delaynode)
{
    Abc_Obj_t *pNode1 = NULL, *pNode2 = NULL;
    if (pNode->Level == 1)
    {
        return;
    }
    if (pNode->vFanins.nSize == 0)
    {
        return;
    }
    //判断节点层级是否相等
    if (Abc_ObjFanin0(pNode)->Level != Abc_ObjFanin1(pNode)->Level)
    {
        //选取层级较高的节点作为下一个探索初始节点
        pNode = Abc_ObjFanin0(pNode)->Level > Abc_ObjFanin1(pNode)->Level ? Abc_ObjFanin0(pNode) : Abc_ObjFanin1(pNode);
        SaveNoDuplicationId(pNode, delaynode);
        getCriticalPath(pNode, delaynode);
    }
    else
    {
        pNode1 = Abc_ObjFanin0(pNode);
        pNode2 = Abc_ObjFanin1(pNode);
        SaveNoDuplicationId(pNode1, delaynode);
        getCriticalPath(pNode1, delaynode);
        SaveNoDuplicationId(pNode2, delaynode);
        getCriticalPath(pNode2, delaynode);
    }
}
/*------------------------------------------------------------------------*/
/* 保存不重复的关键节点并记录关键节点重复次数                              */
/*------------------------------------------------------------------------*/
void SaveNoDuplicationId(Abc_Obj_t *pNode, DelyNode &delaynode)
{
    int idIsExist = 0;
    for (int i = 0; i < delaynode.pathcone.size(); i++)
    {
        if (delaynode.pathcone[i] == pNode->Id)
        {
            //若该节点在容器中已存在，则将idIsExist置1，并令pNode结构体中临时变量dtemp增加1
            idIsExist = 1;
            pNode->dTemp++;
        }
    }
    if (idIsExist == 0)
    {
        delaynode.pathcone.push_back(pNode->Id);
    }
    else
    {
        idIsExist = 0;
    }
}
/*------------------------------------------------------------------------*/
/* 初始化dtemp值                                                         */
/*------------------------------------------------------------------------*/
void setiTemp(Abc_Ntk_t *pNtk)
{
    Abc_Obj_t *pNode;
    int i = 0;
    Abc_NtkForEachObj(pNtk, pNode, i)
    {
        pNode->dTemp = 1;
    }
}
/*------------------------------------------------------------------------*/
/* 错误率约束优化主程序                                                   */
/*------------------------------------------------------------------------*/
Abc_Ntk_t *GetBestDelayNtk(Abc_Ntk_t *pNtk, DelyNode &delaynode, double bound)
{
    Abc_Ntk_t *ptempNtk = NULL, *pNtk_org = NULL;
    float delay = 0, finaldelay = 0, level = 0;
    double error = 0, Lastrate = 0, finalrate = 0;
    ptempNtk = Abc_NtkDup(pNtk);
    pNtk_org = Abc_NtkDup(pNtk);
    Abc_NtkPrintStats(pNtk_org, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
    pNtk_org = NtktoAig(pNtk_org);
    while (error < bound)
    {
        finalrate = Lastrate;
        level = Abc_NtkLevel(pNtk);
        random_device rd;
        unsigned seed = static_cast<unsigned>(rd());
        cout << "seed :" << seed << endl;
        Abc_NtkDelete(ptempNtk);
        ptempNtk = Abc_NtkDup(pNtk);
        delay = caldelay(pNtk);
        pNtk = GetBestDelayNtk1(pNtk, pNtk_org, Lastrate, bound, seed, delaynode);
        pNtk = NtktoAig(pNtk);
        Lastrate = MeasureER(pNtk, pNtk_org, 102400, seed, false);
        pNtk = NtkStrash(pNtk);
        if (Lastrate > bound)
        {
            pNtk = ptempNtk;
            break;
        }
        finaldelay = caldelay(pNtk);
        if (delay == finaldelay && level == Abc_NtkLevel(pNtk))
        {
            break;
        }
    }
    Abc_NtkPrintStats(pNtk, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
    cout << "final rate: " << finalrate << endl;
    Abc_NtkDelete(pNtk_org);
    return pNtk;
}

/*------------------------------------------------------------------------*/
/* 计算错误率                                                              */
/*------------------------------------------------------------------------*/
Abc_Ntk_t *GetBestDelayNtk1(Abc_Ntk_t *pNtk, Abc_Ntk_t *pNtk_org, double lastError, double bound, unsigned seed, DelyNode &delaynode)
{
    Abc_Obj_t *pNode = NULL;
    Abc_Ntk_t *pNtk_temp = NULL, *pNtk_best = NULL;
    int i = 0, level = 0;
    double weight = 0, error = 0, r = 0, tempweight = 0, bestrate = 0;
    float lastdelay = 0, delay = 0;
    pNtk_temp = Abc_NtkDup(pNtk);
    pNtk_best = Abc_NtkDup(pNtk);
    lastdelay = caldelay(pNtk);
    //清除上一次保存的电路节点信息
    cleardelaynode(pNtk, delaynode);
    setiTemp(pNtk);
    SaveMessage(pNtk, delaynode);
    CalWeight(pNtk, delaynode);
    sortbylevel(pNtk, delaynode);
    for (i = 0; i < Abc_NtkLevel(pNtk); i++)
    {
        Abc_NtkPrintStats(pNtk, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
        level = delaynode.wlevel[i];
        for (int k = 0; k < delaynode.weightcone.size(); k++)
        {
            pNode = Abc_NtkObj(pNtk, delaynode.weightcone[k]);
            if (pNode->Level == level)
            {
                for (int j = 0; j < pNode->vFanouts.nSize; j++)
                    DelayConstreplace(pNtk, pNode, delaynode);
            }
        }
        pNtk = NtkStrash(pNtk);
        //   pNtk = Optimaize_resyn2(pNtk);
        delay = caldelay(pNtk);
        pNtk = NtktoAig(pNtk);
        error = MeasureER(pNtk, pNtk_org, 102400, seed, false);
        pNtk = NtkStrash(pNtk);
        Abc_NtkPrintStats(pNtk, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
        cout << "delay:" << delay << endl;
        cout << "rate: " << error << endl;
        r = error - lastError;
        if (r == 0)
        {
            weight = (lastdelay - delay) * 10000;
        }
        else
        {
            if (error > bound)
            {
                weight = -1;
            }
            else
            {
                //weight = (lastdelay - delay) / r +  (Abc_NtkLevel(pNtk_temp)-Abc_NtkLevel(pNtk))/r;
                weight = (lastdelay - delay) / r ;
            }
        }
        if (weight >= tempweight)
        {
            tempweight = weight;
            Abc_NtkDelete(pNtk_best);
            bestrate = error;
            pNtk_best = Abc_NtkDup(pNtk);
        }
        cout << "weight: " << weight << endl;
        Abc_NtkDelete(pNtk);
        pNtk = Abc_NtkDup(pNtk_temp);
    }
    Abc_NtkDelete(pNtk_temp);
    Abc_NtkPrintStats(pNtk_best, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
    return pNtk_best;
}

/*------------------------------------------------------------------------*/
/* 计算关键路径中各个节点所占权重                                            */
/*------------------------------------------------------------------------*/
void CalWeight(Abc_Ntk_t *pNtk, DelyNode &delaynode)
{
    Abc_Obj_t *pNode = NULL;
    cout <<  delaynode.pathcone.size() << endl;
    //权重值是由该节点在关键路径中遍历累计次数与其所在层级相除所得到的，使用multimap容器进行存储
    for (int i = 0; i < delaynode.pathcone.size(); i++)
    {
        pNode = Abc_NtkObj(pNtk, delaynode.pathcone[i]);
        if (Abc_ObjIsPi(pNode) != 1)
        {
            delaynode.weight.insert(pair<double, int>((1000 / Abc_NtkLevel(pNtk) / pNode->dTemp), Abc_NtkObj(pNtk, delaynode.pathcone[i])->Id));
        }
    }
    //将所得到的排好序的id保存到vector容器中
    for (multimap<double, int>::iterator it = delaynode.weight.begin(); it != delaynode.weight.end(); it++)
    {
        delaynode.weightcone.push_back((*it).second);
    }
}

/*------------------------------------------------------------------------*/
/* 通过weightcone对候选集所处层级进行排序                                  */
/*------------------------------------------------------------------------*/
void sortbylevel(Abc_Ntk_t *pNtk, DelyNode &delaynode)
{
    int count = 0, time = 0, weight = 0;
    Abc_Obj_t *pNode = NULL;
    for (multimap<double, int>::iterator it = delaynode.weight.begin(); it != delaynode.weight.end(); it++)
    {
        pNode = Abc_NtkObj(pNtk, (*it).second);
        int level = pNode->Level;
        delaynode.weightsort.insert(pair<int, int>((*it).first, level));
    }
    for (int i = 1; i < Abc_NtkLevel(pNtk) + 1; i++)
    {
        for (multimap<int, int>::iterator it = delaynode.weightsort.begin(); it != delaynode.weightsort.end(); it++)
        {
            if ((*it).second == i)
            {
                count += (*it).first;
                time++;
            }
        }
        if (time == 0)
            weight = 0;
        else
            weight = count / time;
        delaynode.levelsort.insert(pair<int, int>(weight, i));
        count = 0;
        time = 0;
    }
    for (map<int, int>::iterator it = delaynode.levelsort.begin(); it != delaynode.levelsort.end(); it++)
    {
        delaynode.wlevel.push_back((*it).second);
    }
}

/*------------------------------------------------------------------------*/
/* 常量替换                                                              */
/*------------------------------------------------------------------------*/
void DelayConstreplace(Abc_Ntk_t *pNtk, Abc_Obj_t *pNode, DelyNode &delaynode)
{
    Abc_Obj_t *pRootfanout = NULL;
    int fanoutnum = 0, i = 0;
    fanoutnum = pNode->vFanouts.nSize;
    for (i = 0; i < fanoutnum; i++)
    {
        for (vector<int>::iterator it = delaynode.weightcone.begin(); it != delaynode.weightcone.end(); it++)
        {
            if (Abc_ObjFanout(pNode, i)->Id == (*it))
            {
                pRootfanout = Abc_ObjFanout(pNode, i);
                edgereplace(pNtk, pNode, pRootfanout, delaynode);
                return;
            }
        }
    }
}
/*------------------------------------------------------------------------*/
/* 节点连接变换                                                          */
/*------------------------------------------------------------------------*/
void edgereplace(Abc_Ntk_t *pNtk, Abc_Obj_t *pNode, Abc_Obj_t *pRootfanout, DelyNode &delaynode)
{
    Abc_Obj_t *pNodefanin = NULL;
    for (vector<int>::iterator it = delaynode.weightcone.begin(); it != delaynode.weightcone.end(); it++)
    {
        if ((*it) == Abc_ObjFanin1(pNode)->Id)
        {
            pNodefanin = Abc_NtkObj(pNtk, (*it));
        }
        if ((*it) == Abc_ObjFanin0(pNode)->Id)
        {
            pNodefanin = Abc_NtkObj(pNtk, (*it));
        }
    }
    if (pNode->Level == 1)
        Abc_ObjPatchFanin(pRootfanout, pNode, Abc_ObjFanin0(pNode));
    else
    {
        Abc_ObjPatchFanin(pRootfanout, pNode, pNodefanin);
    }
}
/*------------------------------------------------------------------------*/
/* 获取延迟                                                              */
/*------------------------------------------------------------------------*/
float getdelay(Abc_Ntk_t *pNtk)
{
    float delay = 0;
    pNtk = Ntkmap(pNtk);
    delay = Abc_NtkDelayTrace(pNtk, NULL, NULL, 0);
    pNtk = NtkStrash(pNtk);
    return delay;
}
/*------------------------------------------------------------------------*/
/* 计算延迟                                                              */
/*------------------------------------------------------------------------*/
float caldelay(Abc_Ntk_t *pNtk)
{
    float delay = 0;
    Abc_Ntk_t *pNtk_delay = NULL;
    pNtk_delay = Abc_NtkDup(pNtk);
    delay = getdelay(pNtk_delay);
    Abc_NtkDelete(pNtk_delay);
    return delay;
}
/*------------------------------------------------------------------------*/
/* 类初始化                                                              */
/*------------------------------------------------------------------------*/
void cleardelaynode(Abc_Ntk_t *pNtk, DelyNode &delaynode)
{
    setiTemp(pNtk);
    delaynode.topid.clear();
    delaynode.pathcone.clear();
    delaynode.weightcone.clear();
    delaynode.weight.clear();
    delaynode.levelsort.clear();
    delaynode.weightsort.clear();
    delaynode.wlevel.clear();
}

/*------------------------------------------------------------------------*/
/* 测试程序                                                              */
/*------------------------------------------------------------------------*/
void test(Abc_Ntk_t *pNtk, DelyNode &delaynode)
{
    int i;
    vector<int> temppath;
    cout << "与PO相连节点id: ";
    for (i = 0; i < delaynode.topid.size(); i++)
    {
        cout << delaynode.topid[i] << " ";
    }
    cout << endl;
    cout << "-----------所有关键路径节点总集合------------" << endl;
    for (i = 0; i < delaynode.pathcone.size(); i++)
    {
        cout << delaynode.pathcone[i] << " ";
    }
    cout << endl;
    /*     cout << "---------关键路径途径次数大于0的节点有---------" << endl;
    for (i = 0; i < delaynode.pathcone.size(); i++)
    {
        if (Abc_NtkObj(pNtk, delaynode.pathcone[i])->dTemp > 1)
        {
            cout << "Id: " << Abc_NtkObj(pNtk, delaynode.pathcone[i])->Id << " 次数 " << Abc_NtkObj(pNtk, delaynode.pathcone[i])->dTemp << " ";
        }
    }
    cout << endl; */
    //测试打印模块
    cout << "-----------按照权重从大到小一次排序------------" << endl;
    for (i = 0; i < delaynode.weightcone.size(); i++)
    {
        cout << delaynode.weightcone[i] << " ";
    }
    cout << endl;
    cout << "-----------按照层级权重从大到小排序对层级进行排序------------" << endl;
    for (map<int, int>::iterator it = delaynode.levelsort.begin(); it != delaynode.levelsort.end(); it++)
    {
        cout << "weight: " << (*it).first << " level: " << (*it).second << " ";
    }
    cout << endl;
    cout << "-----------按照层级权重从大到小排序------------" << endl;
    for (i = 0; i < delaynode.wlevel.size(); i++)
    {
        cout << delaynode.wlevel[i] << " ";
    }
    cout << endl;
}
